#ifndef _Scene_H_
#define _Scene_H_

#include <vector>
#include <unordered_map>
#include <math.h>

#include <WinDef.h>
#include <Mmsystem.h>

#include <assimp\scene.h>

#include "Core\Engine.h"
#include "Core\Camera.h"
#include "Core\VertexBuffer.h"
#include "Core\IndexBuffer.h"
#include "Scene\Mesh.h"
#include "Scene\Material.h"
#include "Scene\Light.h"

#define BUCKET_COUNT 1024
#define BUCKET_SIZE  4

class Scene
{
public:
	struct Vertex
    {
            D3DXVECTOR4 position;
            D3DXVECTOR3 normal;
    };

	struct CompareTransparentMeshes
	{
		BOOL operator()(const Mesh* mesh1, const Mesh* mesh2)	// Matrix world transformation ??
		{	
			CONST Camera& camera = Engine::GetInstance().camera();
			FLOAT mesh_1_dist = sqrt(pow(mesh1->center().x - camera.GetPosition().GetX(),2) +
										pow(mesh1->center().y - camera.GetPosition().GetY(),2) +
										pow(mesh1->center().z - camera.GetPosition().GetZ(),2));
			FLOAT mesh_2_dist = sqrt(pow(mesh2->center().x - camera.GetPosition().GetX(),2) +
										pow(mesh2->center().y - camera.GetPosition().GetY(),2) +
										pow(mesh2->center().z - camera.GetPosition().GetZ(),2));
			return mesh_1_dist > mesh_2_dist;
		}
	};

public:
	Scene(Camera* camera);
	~Scene();

	BOOL build(CONST aiScene* ai_scene);

	VOID update();

	VOID newLight();
	VOID deleteLight();

	VertexBuffer& vertexBuffer() CONST;

	CONST std::vector<CONST Light*> lights() CONST;
	CONST std::vector<Material*>& materials() CONST;
	CONST std::vector<Mesh*>& opaqueMeshes() CONST;
	CONST std::vector<Mesh*>& transparentMeshes() CONST;

private:
	std::vector<Vertex>          m_vertices;
	VertexBuffer*                m_vertex_buffer;

	std::vector<Material*>       m_materials;
	std::vector<Mesh*>           m_opaque_meshes;
	std::vector<Mesh*>           m_transparent_meshes;
	std::vector< Mesh* >	     m_sorted_transparent_meshes;

	Camera*						 m_camera;

	Mesh*                        m_buckets[BUCKET_COUNT * BUCKET_SIZE];

	UINT                         m_point_lights_behaviour;
    std::unordered_map<Light*, Matrix4x4> m_lights;

private:
	VOID updateLights();
	VOID sortTransparentMeshes();
};

#endif
